package va;

import bufmgr.*;
import global.*;
import heap.*;
import index.IndexException;
import iterator.*;

import java.io.IOException;

public class BaseIndexScan extends Iterator {

    public Schema schema;
    public String relName;
    public int noInFields;
    public int noOutFields;
    public int fldNum;
    public int count;
    public FldSpec[] perm_mat;
    public CondExpr[] selects;
    public AttrType[] types;
    public short[] str_sizes;
    public Tuple Jtuple;
    public Heapfile f;

    public HFPage currentPage;
    public int currentPid;

    /**
     * class constructor. set up the NN index scan.
     * @param index type of the index (B_Index, Hash, VA_file, none)
     * @param relName name of the input relation
     * @param indexName name of the input index
     * @param types array of types in this relation
     * @param str_sizes array of string sizes (for attributes that are string)
     * @param noInFields number of fields in input tuple
     * @param noOutFields number of fields in output tuple
     * @param outFields fields to project
     * @param selects conditions to apply, first one is primary
     * @param fldNum field number of the indexed field
     * @exception index.IndexException error from the lower layer
     * @exception heap.InvalidTypeException tuple type not valid
     * @exception heap.InvalidTupleSizeException tuple size not valid
     * @exception index.UnknownIndexTypeException index type unknown
     * @exception java.io.IOException from the lower layer
     * @throws WrongPermat 
     * @throws FieldNumberOutOfBoundException 
     * @throws UnknowAttrType 
     * @throws PredEvalException 
     * @throws PageNotReadException 
     * @throws JoinsException 
     * @throws InvalidRelation 
     * @throws TupleUtilsException 
     * @throws FileScanException 
     */
    public BaseIndexScan(IndexType index,
                           String relName,
                           String indexName,
                           AttrType[] types,
                           short[] str_sizes,
                           int noInFields,
                           int noOutFields,
                           FldSpec[] outFields,
                           CondExpr[] selects,
                           int fldNum) throws IndexException, HFException, HFBufMgrException, HFDiskMgrException, IOException, InvalidTupleSizeException, InvalidTypeException, FileScanException, TupleUtilsException, InvalidRelation, JoinsException, PageNotReadException, PredEvalException, UnknowAttrType, FieldNumberOutOfBoundException, WrongPermat {

        this.relName = relName;

        //Paul's code
        //Set up parameters for projection
        this.noInFields = noInFields;
        this.noOutFields = noOutFields;
        this.perm_mat = outFields;
        this.str_sizes = str_sizes;
        this.selects = selects;
        this.fldNum = fldNum;
        this.types = types;

        this.currentPage = new HFPage();
        this.currentPid = -1;

        //number of attribute types for outfield
        AttrType[] Jtypes = new AttrType[this.noOutFields];
        Jtuple = new Tuple(); //this will be the tuple that is formatted as required by the constructor inputs
        
        this.schema = Schema.getSchema(this.relName);

        try{
            //set up the fields of Jtuple according to the inputs into the constructor
            TupleUtils.setup_op_tuple(Jtuple, Jtypes, this.types, this.noInFields, this.str_sizes, perm_mat, this.noOutFields);
        }

        catch (TupleUtilsException e) {
            throw new IndexException(e, "IndexScan.java: TupleUtilsException caught from TupleUtils.setup_op_tuple()");
        }
        catch (InvalidRelation e) {
            throw new IndexException(e, "IndexScan.java: InvalidRelation caught from TupleUtils.setup_op_tuple()");
        }


        try {
            f = new Heapfile(relName);
        }
        catch (Exception e) {
            throw new IndexException(e, "IndexScan.java: Heapfile not created");
        }
    }

    // Function that goes directly to the source in the database to retrieve the tuple, instead of using
    // the heapfile.getRecord() function

    public Tuple getRecordDirect(RID rid) throws Exception {
        if (this.currentPid != rid.pageNo.pid) {
            if (this.currentPid != -1) {
                SystemDefs.JavabaseBM.unpinPage(new PageId(this.currentPid), false);
            }
            this.currentPid = rid.pageNo.pid;
            SystemDefs.JavabaseBM.pinPage(new PageId(this.currentPid), this.currentPage, false);
        }
        Tuple atuple = new Tuple();
        atuple = this.currentPage.getRecord(rid);
        return atuple;
    }

    @Override
    public void close() throws IOException, JoinsException, SortException,
            IndexException, PageUnpinnedException, InvalidFrameNumberException, HashEntryNotFoundException, ReplacerException {
        SystemDefs.JavabaseBM.unpinPage(new PageId(this.currentPid), false);
    }

    //Written by Paul, using IndexScan class as a guide for how to do the projection.
    //The idea is to take the input tuple and project it so it contains only the desired attributes

    public Tuple formatTuple(Tuple tuple) throws IndexException{
        try{
            //Set the header so we know how to do the projection
            tuple.setHdr((short)noInFields, types, str_sizes);
        }

        catch (Exception e) {throw new IndexException(e, "NNIndexScan.java: Heapfile error");
        }

        try{ //project the relevant fields of 'tuple' onto Jtuple
            Projection.Project(tuple, types, Jtuple, perm_mat, noOutFields);
        }

        catch (Exception e) {throw new IndexException(e, "IndexScan.java: Heapfile error");
        }

        return Jtuple;
    }


    @Override
    public Tuple get_next() throws Exception {
        return null;
    }

}
